package configuration;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class DBEntry {
	//Overview: This class provides the leaf nodes of a hash tree like structure
	//Rep(c) = tagDB != null and is initialized && identifier !=null
	//AF(c) = (identifier, {tag : String} onto Values)
	private final ConcurrentHashMap<String, String> tagDB;
	private final String identifier;

	public DBEntry(final String id) {
		//Requires: string !=null
		//Modifies: this
		//Effects: initializes this
		tagDB = new ConcurrentHashMap<String, String>();
		identifier = id;
	}

	public void add(final String tag, final String value) throws EntryExists {
	    //* Requires: true
	    //* Modifies: this
	    //* Effects: Adds (tag, string) to this
		if (tagDB.containsKey(tag)) {
			//We are adding , not changing, we must break and throw exception
			//Otherwise hashmap will simply overwrite
			throw new EntryExists();
		} else {
			tagDB.put(tag, value);
		}
	}

	public String getEntry(final String tag) throws NoEntryException {
	    //* Requires: true
	    //* Modifies: none
	    //* Effects: gets the value associated with tag, if tag does not exist throws NoEntryException
		if (tagDB.containsKey(tag)) {
			return tagDB.get(tag);
		} else {
			throw new NoEntryException();
		}
	}

	public String getID() {
	    //* Requires: true
	    //* Modifies: none
	    //* Effects: Returns identifier associated with this
		return identifier;
	}

	public boolean isTag(final String tag) {
	    //* Requires: true
	    //* Modifies: none
	    //* Effects: returns true if this contains tag, otherwise return false
		if(tag != null){
		return tagDB.containsKey(tag);
		}
		return false;
	}

	public void removeTag(final String key) throws NoEntryException {
	    //* Requires: true
	    //* Modifies: this
	    //* Effects: Removes value associated with the passed key, otherwise throws new NoEntryException
		if (tagDB.containsKey(key)) {
			tagDB.remove(key);
		} else {
			throw new NoEntryException();
		}
	}

	public void changeEntry(final String tag, final String value)
			throws NoEntryException {
	    //* Requires: true
	    //* Modifies: this
	    //* Effects: Changes value associated with given tag, otherwise throws NoEntryException
		if (tagDB.containsKey(tag)) {
			tagDB.replace(tag, value);
		} else {
			throw new NoEntryException();
		}
	}

	public void write(final BufferedWriter notebook) {
	    //* Requires: true
	    //* Modifies: none
	    //* Effects: Writes data to notebook, otherwise pass IOException
		try {
			final HashMap<String, String> temp = new HashMap<String, String>(
					tagDB);
			for (final String key : temp.keySet()) {
				notebook.write("<Tag>");
				notebook.write(key);
				notebook.write("<Value>");
				notebook.write(temp.get(key));
				notebook.write("</Value>");
				notebook.write("</Tag>");
				notebook.newLine();
			}
		} catch (final IOException e) {
			new IOException();
		}
	}

	public Set<String> getTags() {
	    //* Requires: true
	    //* Modifies: none
	    //* Effects: returns tags in this
		return tagDB.keySet();
	}
}